/**
 * ReportGear(2011)
 */
package com.reportgear.report.model.calculator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import com.reportgear.core.data.SalaryHelper;
import com.reportgear.core.data.model.SalaryDataObject;
import com.reportgear.report.model.ReportModel;
import com.reportgear.report.model.cell.Cell;
import com.reportgear.report.model.cell.value.salary.SalaryMainObject;
import com.reportgear.report.model.cell.value.salary.SalaryObject;
import com.reportgear.report.model.cell.value.salary.SalaryObjectType;
import com.reportgear.report.model.cell.value.salary.enhance.OrderObject;
import com.reportgear.report.model.cell.value.support.CommonObject;
import com.sot.core.util.StringUtils;

/**
 * 
 * 工资对象计算，扩展工资对象,支持层次分组
 * 
 * @version 1.0 2011-6-5
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class SalaryObjectCalculator extends AbstractCalculator {
	public SalaryObjectCalculator() {

	}

	@Override
	public ReportModel calculate(ReportModel model, CalcParameter parameter) {
		if (logger.isDebugEnabled()) {
			logger.debug("计算模型：工资对象计算");
		}

		ReportModel calcModel = model;

		this.doCalculate(calcModel, parameter);

		return calcModel;
	}

	/**
	 * 计算
	 * 
	 * @param model
	 *            模型
	 */
	private void doCalculate(ReportModel model, CalcParameter parameter) {
		Iterator<Cell> iter = model.getCellsIteratorByCellElementClass(SalaryObject.class);
		for (Iterator<Cell> i = iter; i.hasNext();) {
			this.calculateCell(model, i.next(), parameter);
		}
	}

	/**
	 * 计算单元格<br/>
	 * 从当前行开始生成SalaryMainObject<br/>
	 * 当前行改变，其它插入,插入行时复制上一行的style
	 * 
	 * @param model
	 *            模型
	 * @param cell
	 *            单元格
	 * @param parameter
	 *            参数信息
	 */
	private void calculateCell(ReportModel model, Cell cell, CalcParameter parameter) {
		List<SalaryDataObject> dataList = SalaryHelper.INSTANCE.getPayObjects(parameter.getPaymentId(), parameter
				.getSalaryObjectType(), parameter.getMaxLevel(), parameter.getObjectSet(), Collections
				.<Integer> emptySet());

		List<SalaryMainObject> roList = new ArrayList<SalaryMainObject>();

		List<Integer> showLevelList = parameter.getShowLevelList();

		for (SalaryDataObject sdo : dataList) {
			CommonObject co = new CommonObject(sdo.getInt("id"), sdo.getInt("parentId"), sdo.getString("code"), sdo
					.getString("name"));

			// 计算是否显示层级
			if (showLevelList.contains(this.getLevel(co.getCode()))) {
				roList.add(new SalaryMainObject(co));
			}
		}

		String key = (parameter.getSalaryObjectType() == SalaryObjectType.ORGANIZATION) ? OrderObject.ORDER_KEY_ORGANIZATION
				: OrderObject.ORDER_KEY_COSTCENTER;

		final List<Integer> idOrderList = new ArrayList<Integer>();
		List<SalaryDataObject> orderInfo = SalaryHelper.INSTANCE.getOrderInfo(key);
		for (SalaryDataObject sdo : orderInfo) {
			idOrderList.add(sdo.getInt("id"));
		}

		// 排序，使用了外部排序和代码排序
		Collections.sort(roList, new Comparator<SalaryMainObject>() {

			@Override
			public int compare(SalaryMainObject s1, SalaryMainObject s2) {
				int id1 = s1.getObject().getId();
				int id2 = s2.getObject().getId();
				int index1 = idOrderList.indexOf(id1);
				int index2 = idOrderList.indexOf(id2);

				if (index1 > -1 && index2 > -1) {
					return index1 - index2;
				} else if (index1 > -1) {
					return -1;
				} else if (index2 > -1) {
					return 1;
				} else {
					return s1.getObject().getCode().compareTo(s2.getObject().getCode());
				}
			}
		});

		int row = cell.getRow();
		int col = cell.getColumn();

		int ptr = row;
		for (SalaryMainObject smo : roList) {
			if (ptr != row) {
				model.addRow(ptr);
				model.copyRowProperties(ptr, ptr - 1);
			}

			model.setCellValue(col, ptr, smo);
			ptr++;
		}
	}

	// 获取对象的层级
	private int getLevel(String code) {
		if (StringUtils.isEmpty(code)) {
			return 0;
		} else {
			return code.split("-").length;
		}
	}
}
